/*
 * 
 * Copyright 2010 David H Pollack
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * 
 */

package fantasy;

import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthUtil;

/**
 * @author dpollack
 *
 */
public class YahooAsyncCalls extends HttpServlet {
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {
		doPost(req, resp);
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {

		PersistenceManager pm = PMF.get().getPersistenceManager();
        
		Properties props = new Properties();
        props.load(this.getClass().getClassLoader().getResourceAsStream("fantasy.properties"));
		
		final String BASEURL = props.getProperty("application.baseurl");
		final String YAHOO_CONSUMER_KEY = props.getProperty("oauth.consumerkey");
		final String YAHOO_CONSUMER_SECRET = props.getProperty("oauth.consumersecret");
		
		String oauth_method = "GET";
		
		UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        
		String apiUrl = URLDecoder.decode(req.getParameter("url"), "US-ASCII");
		
		OAuthParameters gOAuthParamaters = new OAuthParameters();
		
		
		
		Map<String, String> oauthParametersUnencoded = new LinkedHashMap<String, String>();
		SortedMap<String, String> oauthParametersEncoded = new TreeMap<String, String>();

        if (user != null) {

    		Key k = new KeyFactory.Builder(UserTable.class.getSimpleName(), user.getNickname()).getKey();
    		
    		UserTable u = pm.getObjectById(UserTable.class, k);
    		
    		String authData = u.getAuthdata();
    		
    		String[] authParts = authData.split("&");
    		
    		final String YAHOO_ACCESS_TOKEN = authParts[0];
    		final String YAHOO_ACCESS_SECRET = authParts[1];
    		
    		String oauthNonce = OAuthUtil.getNonce();
    		String oauthTimestamp = OAuthUtil.getTimestamp();
    		
    		oauthParametersUnencoded.put("oauth_consumer_key", YAHOO_CONSUMER_KEY);
    		oauthParametersUnencoded.put("oauth_token", YAHOO_ACCESS_TOKEN);
    		oauthParametersUnencoded.put("oauth_nonce", oauthNonce);
    		oauthParametersUnencoded.put("oauth_timestamp", oauthTimestamp);
    		oauthParametersUnencoded.put("oauth_signature_method", "HMAC-SHA1");
    		oauthParametersUnencoded.put("oauth_version", "1.0");
    		
    		oauthParametersEncoded.put("oauth_consumer_key", OAuthUtil.encode(YAHOO_CONSUMER_KEY));
    		oauthParametersEncoded.put("oauth_token", OAuthUtil.encode(YAHOO_ACCESS_TOKEN));
    		oauthParametersEncoded.put("oauth_nonce", OAuthUtil.encode(oauthNonce));
    		oauthParametersEncoded.put("oauth_timestamp", OAuthUtil.encode(oauthTimestamp));
    		oauthParametersEncoded.put("oauth_signature_method", OAuthUtil.encode("HMAC-SHA1"));
    		oauthParametersEncoded.put("oauth_version", OAuthUtil.encode("1.0"));
    		
    		gOAuthParamaters.setOAuthConsumerKey(OAuthUtil.encode(YAHOO_CONSUMER_KEY));
    		gOAuthParamaters.setOAuthToken(OAuthUtil.encode(YAHOO_ACCESS_TOKEN));
    		gOAuthParamaters.setOAuthNonce(OAuthUtil.encode(oauthNonce));
    		gOAuthParamaters.setOAuthTimestamp(OAuthUtil.encode(oauthTimestamp));
    		gOAuthParamaters.setOAuthSignatureMethod("HMAC-SHA1");
    		
    		StringBuilder s = new StringBuilder();
    		
    		Set<String> keys = oauthParametersEncoded.keySet();
    		boolean firstLoop = true;
    		for(String key : keys) {
    			if(!firstLoop) s.append("&");
    			s.append(key);
    			s.append("=");
    			s.append(oauthParametersEncoded.get(key));
    			firstLoop = false;
    			log(key + "=" + oauthParametersEncoded.get(key));
    		}
    		
    		log(s.toString());
    		
    		String baseStringUnencoded = oauth_method + "&" + apiUrl + "&" + s.toString();
    		
    		String baseStringUrlEncoded = OAuthUtil.encode(baseStringUnencoded);
    		
    		String baseStringFromUtil;
    		try {
				baseStringFromUtil = OAuthUtil.getSignatureBaseString(apiUrl, oauth_method, oauthParametersEncoded);
				
			} catch (OAuthException e) {
				// TODO Auto-generated catch block
				baseStringFromUtil = null;
				e.printStackTrace();
			}
    		
			
			log(baseStringUrlEncoded);
			log(baseStringFromUtil);
			
			String hmacAlgoKey = OAuthUtil.encode(YAHOO_CONSUMER_SECRET) + "&" + OAuthUtil.encode(YAHOO_ACCESS_SECRET);
			
			gOAuthParamaters.setOAuthConsumerSecret(YAHOO_CONSUMER_SECRET);
			gOAuthParamaters.setOAuthTokenSecret(YAHOO_ACCESS_SECRET);
			
			String oauth_signature = Base64.encodeBase64URLSafeString(hmacAlgoKey.getBytes()) + "=";
			
			OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
			String oauth_signature2;
			try {
				oauth_signature2 = signer.getSignature(baseStringFromUtil, gOAuthParamaters);
			} catch (OAuthException e) {
				// TODO Auto-generated catch block
				oauth_signature2 = null;
				e.printStackTrace();
			}
			
			log("\n" + hmacAlgoKey + "\n" + oauth_signature);
			log("\n" + oauth_signature + "\n" + oauth_signature2);
			
			gOAuthParamaters.setRealm("yahooapis.com");
			
			gOAuthParamaters.setOAuthSignature(OAuthUtil.encode(oauth_signature2));
			
			
			String oauthHeaderValue = createAuthHeaderValue(gOAuthParamaters);
			
			log("Header: " + oauthHeaderValue);
    		
			makeAsyncRequest(apiUrl, gOAuthParamaters);
    		
    		
        } else {
            resp.sendRedirect(userService.createLoginURL(req.getRequestURI()));
        }

	
	}
	
	private String createAuthHeaderValue(OAuthParameters gOAuthParamaters) {
		// TODO Auto-generated method stub
		
		StringBuilder s = new StringBuilder();
		
		s.append("realm=\"");
		s.append(gOAuthParamaters.getRealm());
		s.append("\",\n");

		s.append("oauth_consumer_key=\"");
		s.append(gOAuthParamaters.getOAuthConsumerKey());
		s.append("\",\n");

		s.append("oauth_token=\"");
		s.append(gOAuthParamaters.getOAuthToken());
		s.append("\",\n");

		s.append("oauth_nonce=\"");
		s.append(gOAuthParamaters.getOAuthNonce());
		s.append("\",\n");

		s.append("oauth_timestamp=\"");
		s.append(gOAuthParamaters.getOAuthTimestamp());
		s.append("\",\n");

		s.append("oauth_signature_method=\"");
		s.append(gOAuthParamaters.getOAuthSignatureMethod());
		s.append("\",\n");

		s.append("oauth_version=\"");
		s.append("1.0");
		s.append("\",\n");

		s.append("oauth_signature=\"");
		s.append(gOAuthParamaters.getOAuthSignature());
		s.append("\"");

		log(s.toString());
		return s.toString();
		
	}

	protected void makeAsyncRequest(String url_string, OAuthParameters gOAuthParamaters) {
		URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
		try {
			
			log(url_string + "\n");
			URL url = new URL(url_string);
			
			HTTPRequest request = new HTTPRequest(url, HTTPMethod.GET);
			
//			request.setHeader(new HTTPHeader("Authorization", "OAuth realm=\"" + gOAuthParamaters.getRealm() + "\""));
			request.setHeader(new HTTPHeader("Authorization", "OAuth"));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_consumer_key=\"" + gOAuthParamaters.getOAuthConsumerKey() + "\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_token=\"" + gOAuthParamaters.getOAuthToken() + "\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_nonce=\"" + gOAuthParamaters.getOAuthNonce() + "\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_timestamp=\"" + gOAuthParamaters.getOAuthTimestamp() + "\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_signature_method=\"" + gOAuthParamaters.getOAuthSignatureMethod() + "\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_version=\"1.0\""));
//			request.addHeader(new HTTPHeader("Authorization", "oauth_signature=\"" + gOAuthParamaters.getOAuthSignature() + "\""));
			
			List<HTTPHeader> reqHeaders = request.getHeaders();
			log("Request Headers: ");
			for(HTTPHeader header : reqHeaders) {
				String headerName = header.getName();
				String headerValue = header.getValue();
				
				log(headerName + ": " + headerValue);
			}

			
			Future<HTTPResponse> future = fetcher.fetchAsync(request);
			


			// Other stuff can happen here!

			HTTPResponse response = future.get();
			byte[] content = response.getContent();
			URL finalUrl = response.getFinalUrl();
			int responseCode = response.getResponseCode();
			List<HTTPHeader> headers = response.getHeaders();

			log("Response Headers: ");
			for(HTTPHeader header : headers) {
				String headerName = header.getName();
				String headerValue = header.getValue();
				
				log(headerName + ": " + headerValue);
			}
			
			log(new String(content));

		} catch (IOException e) {
			// new URL throws MalformedUrlException, which is impossible for us here
		} catch (InterruptedException e) {
			// Exception from using java.concurrent.Future
		} catch (ExecutionException e) {
			// Exception from using java.concurrent.Future
			e.printStackTrace();
		}

	}

	

}
